﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Drawing;
using System.Drawing.Drawing2D; 
//using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using Microsoft.SqlServer.Types;

namespace WindowsFormsApplication1
{
    public partial class ShapeDesigner : Form
    {
        Size pb;
        bool ControlPressed = false;
        bool ShiftPress = false;
        bool freehand = true;
        bool isOverPicture = false;
        bool loadGrid = false;

        bool drawing = false;
        PointF lastPointF;
        //Graphics G;
        int paintCount = 0;

        //Size of the drawing pane
        Size DrawingSize;

        PointF minPointF = PointF.Empty;
        PointF maxPointF = PointF.Empty;
        PointF currentPoint;
        Guid currentIndex = Guid.NewGuid();
        SqlGeometry BB = null;

        Guid selectionShape = Guid.NewGuid();

        Dictionary<Guid, GeomInfo> lines;

        PointF Origin;

        Point Scrolls;
        /// <summary>
        /// 
        /// </summary>
        public enum GeomType
        {
            selection
           ,
            tesselation
                , drawing
        }
        public class GeomInfo
        {
            public Guid key;

            private int _level;
            public int Level { get { return _level; } }

            private GeomType _type;
            public GeomType Type { get { return _type; } }

            bool IsDirty = false;
            private SqlGeometry _Geom;
            private List<GraphicsPath> _paths;
            //private double _scale;
            private bool _isSelected;
            public bool IsSelected
            {
                get { return _isSelected; }
                set { _isSelected = value; }
            }
            public GraphicsPath CurrentPath
            {
                get
                {
                    return _paths[_paths.Count - 1];
                }
            }
            public SqlGeometry Geom
            {
                get
                {
                    if (IsDirty || _Geom == null)
                    {
                        SqlGeometry masterGeom = null;
                        foreach (GraphicsPath path in _paths)
                        {
                            string[] Points = new string[(path.PointCount)];
                            int PointCount = 0;
                            PointF lastP = PointF.Empty;
                            for (int pIndex = 0; pIndex < (path.PointCount); pIndex++)
                            {
                                PointF thisP = path.PathPoints[pIndex];
                                if (lastP != thisP)
                                {
                                    Points[PointCount] = string.Format("{0} {1}", thisP.X, thisP.Y);

                                    PointCount++;
                                    lastP = thisP;
                                }
                            }

                            string geoType = "";
                            if (path.PointCount == 0)
                                geoType = "";
                            else if (path.PathTypes[path.PathTypes.Length - 1] == 0 || PointCount == 1)
                                geoType = "Point ({0})";
                            else if ((path.PathTypes[path.PathTypes.Length - 1] & 128) == 0)
                                geoType = "LINESTRING ({0})";
                            else
                                geoType = "POLYGON (({0}))";

                            string geoText = String.Format(geoType, String.Join(",", Points, 0, PointCount));

                            try
                            {
                                SqlGeometry thisGeom = SqlGeometry.Parse(geoText);


                                if (masterGeom == null || SqlGeometry.Null.STEquals(masterGeom))
                                    masterGeom = thisGeom;
                                else
                                    masterGeom = thisGeom.STUnion(masterGeom);
                            }
                            catch (Exception ex)
                            {
                                masterGeom = SqlGeometry.Null;
                            }
                        }
                        _Geom = masterGeom;
                        //  if (_Geom.STIsValid() )                        _paths = GraphicsPathFromGeometry(scale, _Geom);

                        if (!_Geom.IsNull) IsDirty = false;
                    }

                    return _Geom;

                }
                set
                {
                    _Geom = value;

                    ///TODO build the gaphics paths
                    _paths = GraphicsPathFromGeometry(value);
                }
            }

            public string Friendly
            {
                get
                {
                    var Complete = Geom.ToString();
                    return Complete.Length > 1000 ? Complete.Substring(0, 1000) : Complete;
                }
            }

            public SqlDouble Area { get { return Geom.STIsValid() ? Geom.STArea() : 0; } }
            public SqlDouble Length { get { return Geom.STIsValid() ? Geom.STLength() : 0; } }
            public bool IsValid { get { return (bool)Geom.STIsValid(); } }
            public SqlString GeomName { get { return Geom.STIsValid() ? Geom.STGeometryType() : ""; } }
            //            public double scale {get{return _scale ;} set {_scale = value;} }

            public List<GraphicsPath> Path { get { return _paths; } }

            public void Clear()
            {
                _paths = new List<GraphicsPath>();
                _paths.Add(new GraphicsPath());
                _Geom = null;
            }

            public void AddPoint(PointF p)
            {
                Console.WriteLine(String.Format("Add Point To {0}, {1},{2}", this.key, p.X, p.Y));

                //Add point to the Geometry (not easy)
                if (CurrentPath.PointCount == 0 || !CurrentPath.PathPoints[CurrentPath.PointCount - 1].Equals(p))
                {
                    
                    _paths[_paths.Count - 1].AddLine(p, p);

                    IsDirty = true;
                }

            }
            public void CloseShape()
            {
                if (CurrentPath.PointCount >= 3)
                {
                    AddPoint(_paths[_paths.Count - 1].PathPoints[0]);

                    CurrentPath.CloseFigure();
                }
            }

            public GeomInfo(Guid newkey, GeomType type)
            {
                _isSelected = false;
                _level = -1;
                _paths = new List<GraphicsPath>();
                _paths.Add(new GraphicsPath());
                _type = type;
                key = newkey;
            }
            public GeomInfo(Guid newkey, int Level, GeomType type, SqlGeometry Geometry, double scale)
            {
                _isSelected = false;
                _type = type;
                if (newkey == Guid.Empty)
                    this.key = Guid.NewGuid();
                else
                    this.key = newkey;
                _level = Level;
                this.Geom = Geometry;

            }
        }


        /// <summary>
        /// Form constructor
        /// </summary>
        public ShapeDesigner()
        {
            InitializeComponent();

            btnAddGeom.Enabled = false;

            //     G = DrawingPan.CreateGraphics();

            DrawingPan.MouseWheel += new MouseEventHandler(DrawingPan_MouseWheel);
            this.DrawingPan.Paint += new System.Windows.Forms.PaintEventHandler(this.DrawingPan_Paint);
            this.DrawingPan.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DrawingPan_MouseUp);
            this.DrawingPan.MouseDown += new MouseEventHandler(DrawingPan_MouseDown);
            this.DrawingPan.MouseWheel += new MouseEventHandler(DrawingPan_MouseWheel);
            this.DrawingPan.MouseMove += new MouseEventHandler(DrawingPan_MouseMove);
            this.DrawingPan.MouseLeave += new EventHandler(DrawingPan_MouseLeave);
            this.KeyPreview = true;
            this.KeyUp += new KeyEventHandler(Form1_KeyUp);
            this.MouseWheel += new MouseEventHandler(Form1_MouseWheel);
            this.GridGeometries.KeyUp += new KeyEventHandler(GridGeometries_KeyUp);


            this.cntxtGridMenu.Items.Add("STDifference", null, GridOperation_Click);
            this.cntxtGridMenu.Items.Add("STIntersection", null, GridOperation_Click);
            this.cntxtGridMenu.Items.Add("STSymDifference", null, GridOperation_Click);
            this.cntxtGridMenu.Items.Add("STUnion", null, GridOperation_Click);

            this.cntxtGridMenu.Items.Add("STEnvelope", null, GridSIngleOperation_Click);
            this.cntxtGridMenu.Items.Add("STExteriorRing", null, GridSIngleOperation_Click);
            this.cntxtGridMenu.Items.Add("STPointOnSurface", null, GridSIngleOperation_Click);
            this.cntxtGridMenu.Items.Add("STReduce", null, GridSIngleOperation_Click);
            this.cntxtGridMenu.Items.Add("STBuffer", null, GridSIngleOperation_Click);

            

            DrawingWindow.AutoScroll = true;
            DrawingPan.Location = new Point(0, 0);
            DrawingPan.Size = new Size(DrawingWindow.Width - 10, DrawingWindow.Height - 10);
            DrawingSize = DrawingPan.Size;

            pb = DrawingPan.Size;

            GridGeometries.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
            GridGeometries.AutoGenerateColumns = false;
            DataGridViewColumn col = new DataGridViewTextBoxColumn();
            col.Name = "Geometry";
            col.DataPropertyName = "Friendly";
            col.ReadOnly = true;
            col.SortMode = DataGridViewColumnSortMode.Automatic;
            col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
            col.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
            col.Width = 300;
            GridGeometries.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.Name = "Area";
            col.DataPropertyName = "Area";
            col.ReadOnly = true;
            col.SortMode = DataGridViewColumnSortMode.Automatic;
            GridGeometries.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.Name = "Length";
            col.DataPropertyName = "Length";
            col.ReadOnly = true;
            col.SortMode = DataGridViewColumnSortMode.Automatic;
            GridGeometries.Columns.Add(col);

            col = new DataGridViewCheckBoxColumn();
            col.Name = "IsValid";
            col.DataPropertyName = "IsValid";
            col.ReadOnly = true;
            col.SortMode = DataGridViewColumnSortMode.Automatic;
            GridGeometries.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.Name = "Level";
            col.DataPropertyName = "Level";
            col.ReadOnly = true;
            col.SortMode = DataGridViewColumnSortMode.Automatic;
            GridGeometries.Columns.Add(col);


            lines = new Dictionary<Guid, GeomInfo>();

            SetOrigin(new PointF(0, DrawingPan.DisplayRectangle.Height));
        }

        void GridGeometries_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                DeleteGridRows();

            }
        }

        void Form1_MouseWheel(object sender, MouseEventArgs e)
        {

            if (isOverPicture) DrawingPan_MouseWheel(sender, e);
        }


        void DrawingPan_MouseWheel(object sender, MouseEventArgs e)
        {
            //if (DateTime.Now.Ticks - WheelDelay < 100000)
            //    return;

            //WheelDelay = DateTime.Now.Ticks;

            int scroll = e.Delta;

            if (ControlPressed)
            {
                decimal newvalue = numZoom.Value + numZoom.Increment * e.Delta/Math.Abs (e.Delta);
                Zoom(new Point(e.X, e.Y), newvalue);
            }

        }

        private void Zoom(decimal newvalue)
        {
            Zoom(new Point(pb.Width / 2, pb.Height / 2), newvalue);
        }

        bool InZoom=false;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        /// <param name="newvalue"></param>
        private void Zoom(Point e, decimal newvalue)
        {
            if (!InZoom)
            {
                InZoom = true;
                if (newvalue < 0.001m)
                    numZoom.Value = 0.001m;
                else
                    if (numZoom.Value != newvalue)
                        numZoom.Value = newvalue;

                decimal oldvalue = DrawingPan.Size.Width / pb.Width;

                Size newSize = new Size(Convert.ToInt32(pb.Width * numZoom.Value), Convert.ToInt32(pb.Height * numZoom.Value));
                int oldScroll = DrawingWindow.VerticalScroll.Value;

                Size oldSize = DrawingPan.Size;

                DrawingPan.Invalidate();

                if (newSize.Width >= pb.Width)
                {
                    DrawingPan.Size = newSize;
                    PointF p = new PointF(-DrawingWindow.AutoScrollPosition.X + Convert.ToInt32((newSize.Width - oldSize.Width) / ((e.X - DrawingWindow.Left) * 1.0 / pb.Width))
                         , -DrawingWindow.AutoScrollPosition.Y + Convert.ToInt32((newSize.Height - oldSize.Height) / ((e.Y - DrawingWindow.Top) * 1.0 / pb.Height)));


                    int x = Convert.ToInt32(newvalue * ((e.X) - DrawingWindow.AutoScrollPosition.X) / oldvalue - pb.Width / 2);
                    int y = Convert.ToInt32(newvalue * ((e.Y) - DrawingWindow.AutoScrollPosition.Y) / oldvalue - pb.Height / 2);

                    p = new Point(x, y);
                    DrawingPan.Invalidate();

                    DrawingPan.ResumeLayout();
                    //  if (DrawingWindow.VerticalScroll.Visible ) DrawingWindow.VerticalScroll.Value = oldScroll;
                    DrawingWindow.ResumeLayout();

                    //     DrawingWindow.AutoScrollPosition = p;
                    SetOrigin(Origin.X, Origin.Y * (newSize.Height*1.0F / oldSize.Height));
                }
                InZoom = false;
                System.Diagnostics.Debug.Print("Zoom");
            }

        }

        /// <summary>
        /// Handles when the button is pressed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DrawingPan_MouseDown(object sender, MouseEventArgs e)
        {
            Console.WriteLine(string.Format("drawing={0};freehand={1};shiftpress={2}", drawing, freehand, ShiftPress));

            currentPoint = new PointF(e.X, e.Y);
            PointF thisPointF = GetCanvasPointFromMousePoint(e);
                
 
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                
                GeomType shapeType = GeomType.drawing;

                if (!drawing)
                {

                    Guid thisIndex;

                    if (DrawingMode.Text == "Draw")
                    {
                        shapeType = GeomType.drawing;
                        currentIndex = Guid.NewGuid();
                        thisIndex = currentIndex;
                    }
                    else
                    {
                        shapeType = GeomType.selection;

                        thisIndex = selectionShape;
                        currentIndex = thisIndex;
                        if (!ShiftPress && lines.ContainsKey(thisIndex)) lines[thisIndex].Clear();
                    }

                    //else
                    //lines[thisIndex].CurrentPath.StartFigure();

                    //     lines[thisIndex].AddPoint(thisPointF);
                }
                else
                {

                    //     lines[currentIndex].Path.AddLine (thisPointF ,thisPointF);
                }

                if (!lines.ContainsKey(currentIndex))
                    lines.Add(currentIndex, new GeomInfo(currentIndex, shapeType));
                lines[currentIndex].AddPoint(thisPointF);


                drawing = true;
                toolStripIsDrawing.Text = "Drawing";
                freehand = true;
                toolStripDrawingMode.Text = "Freehand";
            }

        }

        /// <summary>
        /// Rounds a value to a grid vertex
        /// </summary>
        /// <param name="value"></param>
        /// <param name="gridSize"></param>
        /// <returns></returns>
        private float RoundToGrid(float value, float gridSize)
        {

            return (float)(gridSize * Math.Round((value / (float)numZoom.Value) / gridSize, 0));
        }

        /// <summary>
        /// Rounds a value to a grid vertex
        /// </summary>
        /// <param name="value"></param>
        /// <param name="gridSize"></param>
        /// <returns></returns>
        private float RoundToGrid(int value, float gridSize)
        {

            return RoundToGrid((float)value, gridSize);
        }

        /// <summary>
        /// Rounds a value to a grid vertex
        /// </summary>
        /// <param name="value"></param>
        /// <param name="gridSize"></param>
        /// <returns></returns>
        private float RoundToGrid(int value, int gridSize)
        {

            return RoundToGrid((float)value, (float)gridSize);
        }

        /// <summary>
        /// Handle the moving of the mouse on the canvas
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DrawingPan_MouseMove(object sender, MouseEventArgs e)
        {
            //Find the current point
            //If snap to grids is on round to the nearest grid vertex


            PointF thisPointF = GetCanvasPointFromMousePoint(e);


            lblCurrentPosition.Text = string.Format("Canvas {0} x {1} Mouse {2}x{3} {4}/{5}", thisPointF.X, thisPointF.Y, e.X, e.Y
                , DrawingWindow.VerticalScroll.Maximum, DrawingWindow.VerticalScroll.Value);

            isOverPicture = true;

            //If we are drawing, we need to record the drawing
            if (drawing && freehand)
            {

                if (lastPointF != thisPointF)
                {
                    //     G.DrawLine(new Pen(Color.Red, 2), thisPointF, thisPointF);

                    Guid thisIndex;
                    if (DrawingMode.Text == "Draw")
                    {
                        thisIndex = currentIndex;
                    }
                    else
                    {
                        thisIndex = selectionShape;
                    }
                    lines[thisIndex].AddPoint(thisPointF);

                    LoadGeometryGrid();
                    //DrawingPan.Invalidate();//new Region (lines[currentIndex ].CurrentPath ));
                    DrawingPan_Paint(null, null);
                    lastPointF = thisPointF;
                }
            }
            else //Otherwise we need to handle selecting of shapes and other hover features
            {
                Boolean changed = false;

                //find the point the mouse is at
                SqlGeometry HitTest = SqlGeometry.Point((double)thisPointF.X, (double)thisPointF.Y, 0);

                //loop through the geometries
                foreach (GeomInfo g in lines.Values)
                {
                    //Verify if the shape intersects the mouse point 
                    if (g.Geom.MakeValid().STIntersects(HitTest))
                    {
                        //If we have a polygon, lets calculate the area
                        if (g.Geom.MakeValid().STGeometryType().ToString().Contains("Polygon"))
                        {
                            DrawingPan.CreateGraphics().DrawString(String.Format("{0}", g.Geom.MakeValid().STArea()), new Font(FontFamily.GenericSansSerif, 10), Brushes.Black, new PointF((float)g.Geom.MakeValid().STCentroid().STX, (float)g.Geom.MakeValid().STCentroid().STY));
                        }

                        //If the user has selected to select shapes on hover
                        if (chkHoverSelect.Checked)
                        {
                            //log that we have found a selection shape
                            changed = changed || !g.IsSelected;

                            //mark the shape as selected.
                            g.IsSelected = true;
                        }
                    }
                    else if (chkHoverSelect.Checked && g.IsSelected)
                    {
                        //If the shape was selected but no longer intersects then we need to unselectd it
                        changed = changed || !g.IsSelected;
                        g.IsSelected = false;
                    }

                    //if we changed stuff lets redraw
                    if (changed)
                        DrawingPan.Invalidate();
                }
            }
        }

        private PointF GetCanvasPointFromMousePoint(MouseEventArgs e)
        {
            PointF thisPointF;
            thisPointF = new PointF((float)e.X, (float)e.Y);


            thisPointF.Y = (Origin.Y - thisPointF.Y); //*(float)numZoom.Value;
            thisPointF.X =  thisPointF.X  - Origin.X; //*(float)numZoom.Value;

            if (chkSnap.Checked)
                thisPointF = new PointF(RoundToGrid(thisPointF.X, (float)numGridSize.Value), RoundToGrid(thisPointF.Y, (float)numGridSize.Value));

            thisPointF.X = thisPointF.X * (float)numScale.Value;
            thisPointF.Y = thisPointF.Y * (float)numScale.Value;
            //thisPointF.X = (thisPointF.X + DrawingWindow.HorizontalScroll.Value) * (float)numZoom.Value ;
            return thisPointF;
        }

        private PointF GetMousePointFromCanvasPoint(PointF e)
        {
            return new PointF((float)e.X / (float)numScale.Value, (float)e.Y / (float)numScale.Value);
        }

        private void DrawingPan_MouseLeave(object sender, EventArgs e)
        {
            lblCurrentPosition.Text = "";

            drawing = false;
            toolStripIsDrawing.Text = "Not Drawing";

            isOverPicture = false;

        }

        private void DrawingPan_MouseUp(object sender, MouseEventArgs e)
        {
            //Console.WriteLine 
            System.Diagnostics.Debug.WriteLine("DrawingPan_MouseUp");

            //PointF thisPointF = new PointF((float)(e.X / numZoom.Value), (float)(e.Y / numZoom.Value));
            PointF thisPointF = GetCanvasPointFromMousePoint(e);
            //   G.DrawLine(new Pen(Color.Red, 2), thisPointF, thisPointF);


            //Is this required, should be handled by the mouse move
            //if (lines.ContainsKey(currentIndex ))
            //lines[currentIndex].AddPoint ( thisPointF);

            if (ShapeType.Text == "polygon" && !ShiftPress)
            {
                int index;
                if (DrawingMode.Text == "Draw")
                    lines[currentIndex].CloseShape();
                else
                    lines[selectionShape].CloseShape();

            }


            if (!ShiftPress)
            {
                drawing = false;
                toolStripIsDrawing.Text = "Not Drawing";
                EndShape();
            }
            else
            {
                freehand = false;
                toolStripDrawingMode.Text = "Line";
            }

            System.Diagnostics.Debug.WriteLine("DrawingPan_MouseUp.Invalidate");
            DrawingPan.Invalidate();

            System.Diagnostics.Debug.WriteLine("DrawingPan_MouseUp.DataSource_Rebind");
            LoadGeometryGrid();


        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DrawingPan_Paint(object sender, PaintEventArgs e)
        {

            //Set the lable displaying the size
            lblWindowSize.Text = string.Format("{0} x {1}", DrawingSize.Width, DrawingSize.Height);


            //Create a bitmap that is w


            //     if (DrawingWindow.AutoScrollPosition.X == 0 && DrawingWindow.AutoScrollPosition.Y == 0 && (Scrolls.X > 40 || Scrolls.Y > 40))
            //       DrawingWindow.AutoScrollPosition = Scrolls;


            Console.WriteLine(string.Format("Paint {0}", DateTime.Now));
            paintCount++;
            //   txtPaint.Text = paintCount.ToString();

            Graphics g = e == null ? DrawingPan.CreateGraphics() : e.Graphics;

   //        Matrix myMatrix = new Matrix();
            Matrix myMatrix = new Matrix(1, 0, 0, -1, 0, 0);
          
            float x = (float)(numZoom.Value) /(float)( numScale.Value );// (DrawingPan.Width - 10) / 4000F;
            float y = x;//(DrawingPan.Height-10)/4000F;
            //g.TranslateTransform(0, 0);

            myMatrix.Scale(x, y, MatrixOrder.Append);



            // Draw the rectangle to the screen again after applying the
            // transform.
            //e.Graphics.Transform = myMatrix;

            Bitmap bmp = new Bitmap((int)(DrawingPan.Width ),(int)( DrawingPan.Height));
            Graphics graph = Graphics.FromImage(bmp);
//            graph.Transform = myMatrix;

            graph.Transform = myMatrix;
            
            graph.TranslateTransform( Origin.X,Origin.Y, MatrixOrder.Append);

            //Visible area = 
            int SizeOrigin =(int) numScale.Value * 10;
            graph.FillEllipse(new SolidBrush(Color.Red), new RectangleF(0 - SizeOrigin / 2, 0 - SizeOrigin / 2, SizeOrigin, SizeOrigin));
                
            #region foreach
            foreach (GeomInfo shapeInfo in lines.Values)
            {
                //      SqlGeometry shape = shapeInfo.Geom;


                Color fillColor = Color.White; ;
                Color PenColor = Color.HotPink;
                int penWidth = 2;
                if (shapeInfo.Type == GeomType.tesselation)
                {
                    switch (shapeInfo.Level)
                    {
                        case 1:
                            fillColor = Color.Red;
                            break;
                        case 2:
                            fillColor = Color.Blue;
                            break;
                        case 3:
                            fillColor = Color.Green;
                            break;
                        case 4:
                            fillColor = Color.Orange;
                            break;
                    }
                    PenColor = Color.Gray;
                }
                else
                {
                    if (shapeInfo.Type == GeomType.selection)
                    {
                        PenColor = Color.Violet;
                        fillColor = Color.Brown;
                    }
                    else
                    {

                        if (shapeInfo.IsSelected)
                        {
                            PenColor = Color.Red;
                            penWidth = 3;
                            fillColor = Color.Orange;
                        }
                        else
                        {
                            PenColor = Color.Black;
                            fillColor = Color.Cyan;
                        }
                    }

                }
                Brush fillBrush = new SolidBrush(Color.FromArgb(33, fillColor));
                Pen linePen = new Pen(PenColor, penWidth / x);

                foreach (GraphicsPath gp in shapeInfo.Path)
                {

                    if (gp.PointCount > 0)
                    {
                        if (gp.PointCount == 2)
                        {
                            PointF cross = GetMousePointFromCanvasPoint(gp.PathPoints[0]);

                            graph.DrawLine(linePen, cross.X - 5 / x, cross.Y - 5 / x, cross.X + 5 / x, cross.Y + 5 / y);
                            graph.DrawLine(linePen, cross.X + 5 / x, cross.Y - 5 / x, cross.X - 5 / x, cross.Y + 5 / y);

                            //Pen pointPen = linePen;
                            //pointPen.StartCap = LineCap.ArrowAnchor;
                            //pointPen.SetLineCap(LineCap.ArrowAnchor, LineCap.ArrowAnchor, DashCap.Flat);

                            //gp.AddString("x", FontFamily.GenericSansSerif, 0, 10, gp.PathPoints[0], StringFormat.GenericDefault);
                            //graph.DrawPath(pointPen, gp);
                        }
                        else
                        {
                            graph.DrawPath(linePen, gp);

                            if ((gp.PathTypes[gp.PointCount - 1] & 128) == 128)
                                graph.FillPath(fillBrush, gp);


                        }
                    }
                }
                // }
            }
#endregion

            g.DrawImage(bmp, new PointF(0, 0));
            bmp.Dispose();
            graph.Dispose();
            //DrawingPan.Scale(new SizeF(x, x));

            //g.DrawImage(bmp, e.ClipRectangle, e.ClipRectangle,GraphicsUnit.Pixel );


            Scrolls = new Point(Math.Abs(DrawingWindow.AutoScrollPosition.X), Math.Abs(DrawingWindow.AutoScrollPosition.Y));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            lines.Clear();

            SqlConnection c = new SqlConnection("Data Source=onarc-katmai;user=sys;pwd=P455w0rd!;initial catalog=geo");

            c.Open();
            //SqlCommand com = new SqlCommand ("select g from (values(geometry::STGeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))',0))) d(g)",c);
            SqlCommand com = new SqlCommand("up_GetTesselations", c);
            com.CommandType = CommandType.StoredProcedure;
            com.CommandTimeout = 300;
            SqlDataAdapter da = new SqlDataAdapter(com);
            DataSet res = new DataSet();
            da.Fill(res);

            BB = null;
            foreach (DataRow row in res.Tables[0].Rows)
            {
                if (!row.IsNull(1))
                {
                    SqlGeometry g = (SqlGeometry)row.ItemArray[1];
                    if (BB == null)
                        BB = g.STEnvelope();
                    else
                        BB = BB.STUnion(g).STEnvelope();
                }
            }
            double scale = Math.Min((pb.Width - 30) / (Double)BB.STPointN(3).STX, (pb.Height - 30) / (Double)BB.STPointN(3).STY);

            foreach (DataRow row in res.Tables[0].Rows)
            {
                if (!row.IsNull(1))
                {

                    SqlGeometry g = (SqlGeometry)row.ItemArray[1];


                    int level = (int)row.ItemArray[0];

                    GeomType gt = level == -1 ? GeomType.drawing : GeomType.tesselation;

                    GeomInfo gi = new GeomInfo(Guid.NewGuid(), level, gt, g, scale);

                    lines.Add(gi.key, gi);

                }
            }
            //res.Close ();
            c.Close();

            //     GridGeometries.DataSource = res.Tables[0];


        }


        /// <summary>
        /// Converts  a Geometry into a graphics Path
        /// </summary>
        /// <param name="scale"></param>
        /// <param name="thisGeom"></param>
        /// <returns></returns>
        private static List<GraphicsPath> GraphicsPathFromGeometry(SqlGeometry thisGeom)
        {
            List<GraphicsPath> gp = new List<GraphicsPath>();

            if (!thisGeom.IsNull)
            {
                thisGeom = thisGeom.MakeValid();
                for (int geomIndex = 0; geomIndex < (Int32)thisGeom.STNumGeometries(); geomIndex++)
                {
                    SqlGeometry subGeom = thisGeom.STGeometryN(geomIndex + 1);


                    GraphicsPath thisPath = new GraphicsPath();

                    if (subGeom.STGeometryType() == "Polygon")
                    {

                        PointF[] Points = PointsFromGeom(subGeom.STExteriorRing());

                        thisPath.AddPolygon(Points);

                        for (int lineIndex = 0; lineIndex < subGeom.STNumInteriorRing(); lineIndex++)
                        {
                            Points = PointsFromGeom(subGeom.STInteriorRingN(lineIndex + 1));

                            thisPath.AddPolygon(Points);
                        }
                    }
                    else
                    {
                        PointF[] Points = PointsFromGeom(subGeom);

                        thisPath.AddLines(Points);
                    }

                    gp.Add(thisPath);

                }
            }
            return gp;
        }

        private static PointF[] PointsFromGeom(SqlGeometry subGeom)
        {
            PointF[] Points;
            Points = new PointF[(Int32)(subGeom.STNumPoints())];

            for (int PointFIndex = 0; PointFIndex < subGeom.STNumPoints(); PointFIndex++)
            {
                SqlGeometry geomPointF = subGeom.STPointN(PointFIndex + 1);
                Points[PointFIndex] = new PointF((float)geomPointF.STX.Value, (float)geomPointF.STY.Value);

            }
            return Points;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //DrawingWindow.Select();
            DrawingPan.Select();
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {

            ControlPressed = (e.KeyCode == Keys.ControlKey);
            ShiftPress = (e.KeyCode == Keys.ShiftKey);

            DrawingWindow.NoScroll = ControlPressed;
        }

        void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey) ControlPressed = false;
            if (e.KeyCode == Keys.ShiftKey)
            {

                if (drawing)
                {
                    if (ShapeType.Text == "polygon" && ShiftPress)
                    {
                        lines[currentIndex].CloseShape();
                        DrawingPan.Invalidate();
                    }

                    drawing = false;
                    toolStripIsDrawing.Text = "Not Drawing";
                    EndShape();

                }
                ShiftPress = false;
                freehand = false;
                toolStripDrawingMode.Text = "Line";
            }

            //Implement backspace for lines
            if (e.KeyCode == Keys.Back)
            {
            }
            DrawingWindow.NoScroll = false;
        }

        private void EndShape()
        {

            if (DrawingMode.Text == "Select")
            {
                if (lines.ContainsKey(selectionShape))
                {
                    SqlGeometry selection = lines[selectionShape].Geom;

                    foreach (DataGridViewRow shape in GridGeometries.Rows)
                    {
                        GeomInfo gi = (GeomInfo)shape.DataBoundItem;

                        if (gi.Type == GeomType.drawing)
                        {
                            SqlGeometry g = gi.Geom;

                            if (!g.STIsValid())
                                g = g.MakeValid();
                            selection = selection.MakeValid();
                            gi.IsSelected = (bool)(selection.STIntersects(g));

                        }
                    }
                    System.Diagnostics.Debug.WriteLine("EndShape.DataSource_Rebind");
                    LoadGeometryGrid();
                    DrawingPan.Invalidate();
                }
            }

        }

        private void LoadGeometryGrid()
        {
            loadGrid = true;

            GridGeometries.DataSource = new List<GeomInfo>(lines.Values).ToArray();

            loadGrid = false;
        }

        private void numZoom_ValueChanged(object sender, EventArgs e)
        {
            ChangeIncrement(numZoom);
            Zoom(numZoom.Value);

        }

        private void DrawingPan_Click(object sender, EventArgs e)
        {
            DrawingPan.Select();
        }

        private void GridGeometries_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            //GeomInfo thisShape = ((GeomInfo)GridGeometries.Rows[e.RowIndex].DataBoundItem);
            //if (thisShape != null)
            // txtCurrentShape.Text = thisShape.Geom.ToString ();

        }

        private void GridGeometries_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
        {

        }

        private void GridGeometries_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void GridGeometries_UserAddedRow(object sender, DataGridViewRowEventArgs e)
        {
            //    e.Row.Cells[1].Value = SqlGeometry.Parse(e.Row.Cells[1].Value.ToString ());
            // GridGeometries.CurrentRow .Cells [1].Value 
        }

        private void txtPaint_TextChanged(object sender, EventArgs e)
        {
           btnAddGeom.Enabled = true;
            bool bAddValid = true;
            btnAddValid.Visible = false;
            StringBuilder errors = new StringBuilder();

            if (txtPaint.Text.Length > 0)
            {
                foreach (string geomText in txtPaint.Text.Split('\n'))
                {
                    if (geomText.Length > 0)
                    {
                        try
                        {
                            SqlGeometry g = SqlGeometry.Parse(geomText);
                            if (g.STIsValid())
                            {

                                btnAddGeom.Enabled = btnAddGeom.Enabled & true;
                            }
                            else
                            {
                                errors.AppendLine(String.Format("Parsed {0} Invalid - Valid = {1}", geomText, g.MakeValid().ToString()));
                                bAddValid = bAddValid & (bool)g.MakeValid().STIsValid();

                                btnAddGeom.Enabled = false;
                            }

                        }
                        catch (Exception ex)
                        {
                            errors.AppendLine(String.Format("Parsed {0} Invalid - Error = {1}", geomText, ex.Message));
                            btnAddGeom.Enabled = false;
                        }
                    }
                }

                if (errors.Length > 0)
                {
                    lblError.Text = errors.ToString();
                    if (bAddValid) btnAddValid.Visible = true;
                }
                else
                    lblError.Text = "Parsed - Valid";
            }
        }

        private void btnAddGeom_Click(object sender, EventArgs e)
        {
            foreach (string geomText in txtPaint.Text.Split('\n'))
            {
                if (geomText.Length > 0)
                {
                    GeomInfo gi = new GeomInfo(Guid.NewGuid(), -1, GeomType.drawing, SqlGeometry.Parse(geomText), 1);
                    lines.Add(gi.key, gi);
                    
                }
            }
            DrawingPan.Invalidate();
            LoadGeometryGrid();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Graphics g = DrawingPan.CreateGraphics();

            g.DrawPolygon(new Pen(Color.Red), new PointF[] { new PointF(0, 0), new PointF(0, 200), new PointF(200, 200), new PointF(200, 0) });
            g.DrawPolygon(new Pen(Color.Blue), new PointF[] { new PointF(220, 220), new PointF(220, 400), new PointF(400, 400), new PointF(400, 220) });

            GraphicsPath gp = new GraphicsPath();



            //gp.AddPolygon((new PointF(400, 0), new PointF(300, 50));
            //gp.AddLines(new PointF[] {new PointF(400, 100), new PointF(400, 150)});
            gp.AddLines(new PointF[] { new PointF(300, 100), new PointF(300, 150), new PointF(100, 300), new PointF(150, 150) });

            g.DrawPath(new Pen(Color.Green), gp);
        }

        private void GridGeometries_SelectionChanged(object sender, EventArgs e)
        {

            grpBufferReduce.Enabled = GridGeometries.SelectedRows.Count == 1;
            
            //    Console.WriteLine("GridGeometries_SelectionChanged");
            txtCurrentShape.Text = "";
            int declareIndex = 1;

            if (!loadGrid)
            {
                foreach (DataGridViewRow row in GridGeometries.Rows)
                {

                    ((GeomInfo)row.DataBoundItem).IsSelected = row.Selected;

            
                }
                DrawingPan.Invalidate();
            }

            StringBuilder sb = new StringBuilder(GridGeometries.SelectedRows.Count);
            StringBuilder sbTSQL = new StringBuilder(GridGeometries.SelectedRows.Count);
            foreach (DataGridViewRow row in GridGeometries.Rows)
            {

                if (row.Selected)
                {
                    sb.AppendLine(((GeomInfo)row.DataBoundItem).Geom.ToString());
                    sbTSQL.AppendFormat("DECLARE @Geom{0} GEOMETRY = '{1}'", declareIndex, ((GeomInfo)row.DataBoundItem).Geom.ToString());
                    sbTSQL.AppendLine();
                    declareIndex++;
                }

            }
            txtCurrentShape.Text = sb.ToString();
            txtTSQL.Text = sbTSQL.ToString();

        }



        private void DrawingWindow_Resize(object sender, EventArgs e)
        {
            DrawingPan.SuspendLayout();
            if (DrawingPan.Width < DrawingWindow.Width - DrawingPan.Left)
                DrawingPan.Width = DrawingWindow.Width - DrawingPan.Left;
            if (DrawingPan.Height < DrawingWindow.Height - DrawingPan.Top)
                DrawingPan.Height = DrawingWindow.Height - DrawingPan.Top;


            DrawingPan.ResumeLayout();
        }

        private void GridGeometries_DataSourceChanged(object sender, EventArgs e)
        {
            //Console.WriteLine("GridGeometries_DataSourceChanged");
            foreach (DataGridViewRow row in GridGeometries.Rows)
            {

                row.Selected = ((GeomInfo)row.DataBoundItem).IsSelected;
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            lines.Clear();
            LoadGeometryGrid();
            DrawingPan.Invalidate();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GridDelete_Click(object sender, EventArgs e)
        {
            DeleteGridRows();
        }

        private void DeleteGridRows()
        {
            //Verify the user wants to delete the rows
            if (GridGeometries.SelectedRows.Count > 0 &&
                MessageBox.Show("This will delete all the selected geometries.Do you want to continue", "Confirm Delete", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                ///Loop through the selected rows and remove them

                foreach (DataGridViewRow row in GridGeometries.SelectedRows)
                {
                    lines.Remove(((GeomInfo)row.DataBoundItem).key);
                }

                ///Reload the grid and redraw the drawing
                LoadGeometryGrid();
                DrawingPan.Invalidate();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GridOperation_Click(object sender, EventArgs e)
        {
            GeomInfo result = new GeomInfo(Guid.NewGuid(), GeomType.drawing);
            string method = ((ToolStripMenuItem)sender).Text;

            StringBuilder TSQLLogDeclare = new StringBuilder();
            StringBuilder TSQLLogCalc = new StringBuilder();
            
            TSQLLogDeclare.AppendLine("--------------------------------------------------------------------------------");
            TSQLLogDeclare.AppendFormat("--  {0} at {1}", method, DateTime.Now);
            TSQLLogDeclare.AppendLine();

            ///Loop through the selected rows and union them
            for (int rowIndex = 0; rowIndex < GridGeometries.SelectedRows.Count; rowIndex++)
            {

                DataGridViewRow row = GridGeometries.SelectedRows[rowIndex];
                GeomInfo geom = ((GeomInfo)row.DataBoundItem);

                TSQLLogDeclare.AppendFormat("DECLARE @Geom{0} GEOMETRY = '{1}'; \n",rowIndex, geom.Geom.MakeValid().ToString());

                if (rowIndex == 0)
                {
                    result.Geom = geom.Geom;
                    TSQLLogCalc.AppendLine("SET @Result = @Geom1;");
                }
                else
                {
                    switch (method)
                    {
                        case "STDifference":
                            result.Geom = result.Geom.STDifference(geom.Geom.MakeValid());
                            break;
                        case "STIntersection":
                            result.Geom = result.Geom.MakeValid();
                            result.Geom = result.Geom.STIntersection(geom.Geom.MakeValid());
                            break;
                        case "STSymDifference":
                            result.Geom = result.Geom.STSymDifference(geom.Geom.MakeValid());
                            break;
                        case "STUnion":
                            result.Geom = result.Geom.STUnion(geom.Geom.MakeValid());
                            break;
                    }
                    TSQLLogCalc.AppendFormat("SET @Result = @Result.{0}(@Geom{1});", method, rowIndex + 1);
                }

                
            }

            TSQLLogDeclare.AppendLine("");
            TSQLLogDeclare.AppendFormat("DECLARE @Result GEOMETRY;", method);
            TSQLLogDeclare.AppendLine("");

            TSQLLogCalc.AppendLine();
            TSQLLogCalc.AppendLine("SELECT @Result");

            TSQLLogDeclare.Append(TSQLLogCalc);
            TSQLLogDeclare.AppendLine("GO");
            TSQLLogDeclare.Append(txtTSQLLog.Text);

            txtTSQLLog.Text = TSQLLogDeclare.ToString();

            lines.Add(result.key, result);

            GridGeometries.ClearSelection();
            result.IsSelected = true;
            ///Reload the grid and redraw the drawing
            LoadGeometryGrid();
            DrawingPan.Invalidate();

        }



        private void GridSIngleOperation_Click(object sender, EventArgs e)
        {


            if (GridGeometries.SelectedRows.Count > 1)
                MessageBox.Show("This operation is only done on the first item in the selection");

            GeomInfo result = new GeomInfo(Guid.NewGuid(), GeomType.drawing);

            DataGridViewRow row = GridGeometries.SelectedRows[0];
            GeomInfo geom = ((GeomInfo)row.DataBoundItem);

            string method = ((ToolStripMenuItem)sender).Text;
            switch (method)
            {
                case "STEnvelope":
                    result.Geom = geom.Geom.MakeValid().STEnvelope();
                    break;
                case "STExteriorRing":
                    result.Geom = geom.Geom.MakeValid().STExteriorRing();
                    break;
                case "STPointOnSurface":
                    result.Geom = geom.Geom.MakeValid().STPointOnSurface();
                    break;

            }

            StringBuilder TSQLLog = new StringBuilder ();
            TSQLLog.Append (txtTSQLLog.Text );
            TSQLLog.AppendLine ("--------------------------------------------------------------------------------");
            TSQLLog.AppendLine(String.Format ("  {0} at {1}",method, DateTime.Now ));
            TSQLLog.AppendLine();
            TSQLLog.AppendLine(String.Format("DECLARE @Geom GEOMETRY = '{0}'", geom.Geom.MakeValid().ToString()));
            TSQLLog.AppendLine(String.Format("DECLARE @Result GEOMETRY = @Geom.{0}", method));

            TSQLLog.AppendLine();
            TSQLLog.AppendLine("SELECT @Result");
            txtTSQLLog.Text = TSQLLog.ToString();

            lines.Add(result.key, result);

            GridGeometries.ClearSelection();
            result.IsSelected = true;

            ///Reload the grid and redraw the drawing
            LoadGeometryGrid();
            DrawingPan.Invalidate();
        }

        private void GridGeometries_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            lines.Remove(((GeomInfo)e.Row.DataBoundItem).key);
        }


        /// <summary>
        /// Handles when the button is released and the mouse is on the grid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GridGeometries_MouseUp(object sender, MouseEventArgs e)
        {
            //Only handle if the right button was released
            if (e.Button == MouseButtons.Right)
            {

                // Point where the mouse is clicked.
                Point p = new Point(e.X, e.Y);

                // Get the node that the user has clicked.
                DataGridView.HitTestInfo hi = GridGeometries.HitTest(p.X, p.Y);

                //If the mouse was over a grid row do something
                if (hi.RowIndex >= 0)
                {

                    DataGridViewRow row = GridGeometries.Rows[hi.RowIndex];
                    if ((ControlPressed || ShiftPress) && row.Selected)
                    {
                        //Use selected 
                    }
                    else
                    {
                        //Deselect all the selected items  and select the item over 
                        //which the mouse was released
                        GridGeometries.ClearSelection();
                        row.Selected = true;

                    }

                    //Show the context menu
                    cntxtGridMenu.Show(GridGeometries, p);

                }
            }

        }

        private void btnAddValid_Click(object sender, EventArgs e)
        {


            if (txtPaint.Text.Length > 0)
            {
                foreach (string geomText in txtPaint.Text.Split('\n'))
                {
                    if (geomText.Length > 0)
                    {
                        try
                        {
                            SqlGeometry g = SqlGeometry.Parse(geomText);


                            if (!g.STIsValid())
                            {
                                g = g.MakeValid();
                            }
                            GeomInfo gi = new GeomInfo(Guid.NewGuid(), -1, GeomType.drawing, g, 1);
                            lines.Add(gi.key, gi);

                        }
                        catch (Exception ex)
                        {

                        }
                    }
                }
                DrawingPan.Invalidate();
            }
        }

        private void ShapeType_SelectedIndexChanged(object sender, EventArgs e)
        {
            chkCloseShapes.Enabled = (ShapeType.Text != "polygon");

        }

        private void DrawingMode_SelectedIndexChanged(object sender, EventArgs e)
        {
          ShiftPress = false;
        }

        private void mnuSetOrigin_Click(object sender, EventArgs e)
        {
            SetOrigin (currentPoint);
            
        }


        private void mnuFillCanvas_Click(object sender, EventArgs e)
        {
            if (GridGeometries.SelectedRows.Count > 0)
            {
                SqlGeometry allGeoms=null;
                for (int i = 0; i < GridGeometries.SelectedRows.Count ; i++)
                {
                    GeomInfo gi = (GeomInfo)GridGeometries.SelectedRows[i].DataBoundItem;
                    if (i == 0)
                    {
                        allGeoms = gi.Geom ;
                    }
                    else
                    {
                        allGeoms = allGeoms.STUnion (gi.Geom );
                    }
                }
                if (allGeoms != null)
                {
                    var boundary = allGeoms.MakeValid().STEnvelope();
                    if (boundary.STNumPoints() > 0)
                    {
                        RectangleF boundingBox = GetBoundingRectangleFromGeom(boundary);
                        
                        //Now zoom
                       var scale = (int)Math.Max((boundingBox.Width ) / DrawingPan.DisplayRectangle.Width
                            , (boundingBox.Height) / DrawingPan.DisplayRectangle.Height) + 1;


                        numScale.Value = scale;
                        SetOrigin(new PointF(-((boundingBox.Right + boundingBox.Left) / scale - DrawingPan.DisplayRectangle.Width) / 2
                                            , ((boundingBox.Top + boundingBox.Bottom) / scale + DrawingPan.DisplayRectangle.Height) / 2));
                        

                    }
                }
            }

        }

        private static RectangleF GetBoundingRectangleFromGeom(SqlGeometry boundary)
        {
            var firstP = boundary.STPointN(1);
            System.Diagnostics.Debug.WriteLine(string.Format("{0},{1}", firstP.STX, firstP.STY));
            float minX = (float)firstP.STX, minY = (float)firstP.STY, maxY = minY, maxX = minX;

            for (int i = 2; i <= boundary.STNumPoints(); i++)
            {
                var thisP = boundary.STPointN(i);
                minX = Math.Min(minX, (float)thisP.STX.Value);
                maxX = Math.Max(maxX, (float)thisP.STX.Value);
                minY = Math.Min(minY, (float)thisP.STY.Value);
                maxY = Math.Max(maxY, (float)thisP.STY.Value);
                System.Diagnostics.Debug.WriteLine(string.Format("{0},{1}", thisP.STX, thisP.STY));
            }

            RectangleF boundingBox = new RectangleF(minX, minY, maxX - minX, maxY - minY);
            return boundingBox;
        }

        private void numScale_ValueChanged(object sender, EventArgs e)
        {
            
            ChangeIncrement(numScale);
            DrawingPan.Invalidate();

        }

        private static void ChangeIncrement(NumericUpDown n)
        {
            n.Increment = (decimal)Math.Pow(10, (((int)n.Value ).ToString().Length - 1));
            
        }

        private void numOriginX_ValueChanged(object sender, EventArgs e)
        {
            ChangeIncrement(numOriginX );
            SetOrigin((float)numOriginX.Value, Origin.Y);
        }

        public void SetOrigin(float X,float Y)
        {
            ChangeIncrement(numOriginY );
            SetOrigin(new PointF(X,Y));
        }
        bool bIgnoreOriginChange = false;
        public void SetOrigin(PointF newOrigin)
        {
            if (!bIgnoreOriginChange)
            {
                bIgnoreOriginChange = true;
                Origin = newOrigin;
                numOriginX.Value = (decimal)Origin.X;
                numOriginY.Value = (decimal)Origin.Y;
                DrawingPan.Invalidate();
                bIgnoreOriginChange = false;
            }
        }

        private void numOriginY_ValueChanged(object sender, EventArgs e)
        {
            SetOrigin(Origin.X,(float)numOriginY.Value);
        
        }

        private void btnBuffer_Click(object sender, EventArgs e)
        {
            try
            {
                var thisRow = GridGeometries.SelectedRows[0];

                var Geom = (GeomInfo)thisRow.DataBoundItem;

                SqlGeometry  ShapeToBuffer ;
                if (!Geom.Geom.STIsValid())
                    ShapeToBuffer = Geom.Geom.MakeValid();
                else
                    ShapeToBuffer = Geom.Geom;

                if (ShapeToBuffer.STNumPoints() > 100)
                {
                    var response = MessageBox.Show("Your shape has > 100 points and so buffering may take some time, do you want to continue", "Buffer shape", MessageBoxButtons.YesNo);

                    if (response != System.Windows.Forms.DialogResult.Yes)
                        return;
                }

                var newGeom = ShapeToBuffer.STBuffer((double)numBuffer.Value);

                StoreChangedShape(Geom, newGeom);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format ("Sorry an error occurred \n {0}",ex.Message ));
            }


        }

        private void btnReduce_Click(object sender, EventArgs e)
        {
            try
            {
                var thisRow = GridGeometries.SelectedRows[0];

                var Geom = (GeomInfo)thisRow.DataBoundItem;

                SqlGeometry ShapeToBuffer;
                if (!Geom.Geom.STIsValid())
                    ShapeToBuffer = Geom.Geom.MakeValid();
                else
                    ShapeToBuffer = Geom.Geom;

                if (ShapeToBuffer.STNumPoints() > 100)
                {
                    var response = MessageBox.Show("Your shape has > 100 points and so buffering may take some time, do you want to continue", "Buffer shape", MessageBoxButtons.YesNo);

                    if (response != System.Windows.Forms.DialogResult.Yes)
                        return;
                }

                var newGeom = ShapeToBuffer.Reduce((double)numBuffer.Value);

                StoreChangedShape(Geom, newGeom);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Sorry an error occurred \n {0}", ex.Message));
            }


        }
        private void StoreChangedShape(GeomInfo Geom, SqlGeometry newGeom)
        {

            if (chkBoxOveright.Checked)
            {
                lines[Geom.key].Geom = newGeom;
            }
            else
            {
                var gi = new GeomInfo(Guid.NewGuid(), GeomType.drawing);
                gi.Geom = newGeom;
                lines.Add(gi.key, gi);
            }
            DrawingPan.Invalidate();
            LoadGeometryGrid();
        }

    }
}
